﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management;
using System.Text;
using WMI.NET.Abstracts;
using WMI.NET.CIM;

namespace WMI.NET.ComputerSystemHardware.Printing
{
    /// <summary>
    /// The Win32_Printer WMI class represents a device connected to a computer running on a Microsoft Windows operating system that can produce a printed image or text on paper or other medium.
    /// </summary>
    public class Win32_Printer : CIM_Printer
    {

        private Nullable<UInt32> _Attributes;
        private Nullable<UInt32> _AveragePagesPerMinute;
        private string _Comment;
        private Nullable<Boolean> _Default;
        private Nullable<UInt32> _DefaultPriority;
        private Nullable<Boolean> _Direct;
        private Nullable<Boolean> _DoCompleteFirst;
        private string _DriverName;
        private Nullable<Boolean> _EnableBIDI;
        private Nullable<Boolean> _EnableDevQueryPrint;
        private Nullable<UInt16> _ExtendedDetectedErrorState;
        private Nullable<UInt16> _ExtendedPrinterStatus;
        private Nullable<Boolean> _Hidden;
        private Nullable<Boolean> _KeepPrintedJobs;
        private Nullable<Boolean> _Local;
        private string _Location;
        private Nullable<Boolean> _Network;
        private string _Parameters;
        private string _PortName;
        private string[] _PrinterPaperNames;
        private Nullable<UInt32> _PrinterState;
        private string _PrintJobDataType;
        private string _PrintProcessor;
        private Nullable<UInt32> _Priority;
        private Nullable<Boolean> _Published;
        private Nullable<Boolean> _Queued;
        private Nullable<Boolean> _RawOnly;
        private string _SeparatorFile;
        private string _ServerName;
        private Nullable<Boolean> _Shared;
        private string _ShareName;
        private Nullable<Boolean> _SpoolEnabled;
        private Nullable<DateTimeOffset> _StartTime;
        private Nullable<DateTimeOffset> _UntilTime;
        private Nullable<Boolean> _WorkOffline;

        /// <summary>
        /// Bitmap of attributes for a Windows-based printing device.
        /// </summary>
        public Nullable<UInt32> Attributes { get { return _Attributes; } } //TODO enum

        /// <summary>
        /// Printing rate, in average number of pages per minute, that a printer can produce output.
        /// </summary>
        public Nullable<UInt32> AveragePagesPerMinute { get { return _AveragePagesPerMinute; } }

        /// <summary>
        /// Comment for a print queue.
        /// Example: Color printer
        /// </summary>
        public string Comment { get { return _Comment; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer is the default printer.
        /// </summary>
        public Nullable<Boolean> Default { get { return _Default; } }

        /// <summary>
        /// Default priority value assigned to each print job.
        /// </summary>
        public Nullable<UInt32> DefaultPriority { get { return _DefaultPriority; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the print job is sent directly to the printer. If FALSE, the print job is spooled. 
        /// </summary>
        public Nullable<Boolean> Direct { get { return _Direct; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer starts jobs that are finished spooling. If FALSE, the printer starts jobs in the order that the jobs are received. 
        /// </summary>
        public Nullable<Boolean> DoCompleteFirst { get { return _DoCompleteFirst; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Name of the Windows printer driver.
        /// Example: Windows Fax Driver
        /// </summary>
        public string DriverName { get { return _DriverName; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer can print bidirectionally. 
        /// </summary>
        public Nullable<Boolean> EnableBIDI { get { return _EnableBIDI; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer holds documents in the queue when document and printer setups do not match. 
        /// </summary>
        public Nullable<Boolean> EnableDevQueryPrint { get { return _EnableDevQueryPrint; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Reports standard error information. Additional information should be recorded in DetectedErrorState. 
        /// </summary>
        public Nullable<UInt16> ExtendedDetectedErrorState { get { return _ExtendedDetectedErrorState; } } //TODO enum

        /// <summary>
        /// Status information for a printer that is different from information specified in the Availability property.
        /// </summary>
        public Nullable<UInt16> ExtendedPrinterStatus { get { return _ExtendedPrinterStatus; } }  //TODO enum

        /// <summary>
        /// If TRUE, the printer is hidden from network users.
        /// </summary>
        public Nullable<Boolean> Hidden { get { return _Hidden; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the print spooler does not delete the completed jobs.
        /// </summary>
        public Nullable<Boolean> KeepPrintedJobs { get { return _KeepPrintedJobs; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer is not attached to a network. If both the Local and Network properties are set to TRUE, then the printer is a network printer.
        /// </summary>
        public Nullable<Boolean> Local { get { return _Local; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Physical location of the printer.
        /// Example: Bldg. 38, Room 1164
        /// </summary>
        public string Location { get { return _Location; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer is a network printer. If both the Local and Network properties are set to TRUE, then the printer is a network printer.
        /// </summary>
        public Nullable<Boolean> Network { get { return _Network; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Optional parameters for the print processor.
        /// Example: Copies=2
        /// </summary>
        public string Parameters { get { return _Parameters; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Port that is used to transmit data to a printer. If a printer is connected to more than one port, the names of each port are separated by commas.
        /// Example: LPT1:, LPT2:, LPT3:
        /// </summary>
        public string PortName { get { return _PortName; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Array of paper sizes supported by the printer. The printer-specified names are used to represent supported paper sizes.
        /// Example: B5 (JIS)
        /// </summary>
        public string[] PrinterPaperNames { get { return _PrinterPaperNames; } }

        /// <summary>
        /// One of the possible states relating to this printer. This property is obsolete. In place of this property, use PrinterStatus.
        /// </summary>
        public Nullable<UInt32> PrinterState { get { return _PrinterState; } } //TODO enum

        /// <summary>
        /// Data type of a print job waiting for the Windows-based printing device.
        /// </summary>
        public string PrintJobDataType { get { return _PrintJobDataType; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Name of the print spooler that handles print jobs.
        /// Example: SPOOLSS.DLL
        /// </summary>
        public string PrintProcessor { get { return _PrintProcessor; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Priority of the printer. Jobs on a higher priority printer are scheduled first.
        /// </summary>
        public Nullable<UInt32> Priority { get { return _Priority; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer is published in the network directory service.
        /// </summary>
        public Nullable<Boolean> Published { get { return _Published; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer buffers and queues print jobs.
        /// </summary>
        public Nullable<Boolean> Queued { get { return _Queued; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, the printer accepts only raw data to be spooled.
        /// </summary>
        public Nullable<Boolean> RawOnly { get { return _RawOnly; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Name of the file used to create a separator page. This page is used to separate print jobs sent to the printer.
        /// </summary>
        public string SeparatorFile { get { return _SeparatorFile; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Name of the server that controls the printer. If this string is NULL, the printer is controlled locally.
        /// </summary>
        public string ServerName { get { return _ServerName; } }

        /// <summary>
        /// If TRUE, the printer is available as a shared network resource.
        /// </summary>
        public Nullable<Boolean> Shared { get { return _Shared; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Share name of the Windows-based printing device.
        /// Example: \\PRINTSERVER1\PRINTER2
        /// </summary>
        public string ShareName { get { return _ShareName; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// This property is obsolete; do not use. If TRUE, spooling is enabled for printer.
        /// </summary>
        public Nullable<Boolean> SpoolEnabled { get { return _SpoolEnabled; } }

        /// <summary>
        /// Date and time that a printer can start to print a job—if the printer is limited to print at specific times. This value is expressed as the time elapsed since 12:00 AM GMT (Greenwich Mean Time).
        /// </summary>
        public Nullable<DateTimeOffset> StartTime { get { return _StartTime; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// Date and time that a printer can print the last job—if the printer is limited to print at specific times. This value is expressed as the time elapsed since 12:00 AM GMT (Greenwich Mean Time).
        /// </summary>
        public Nullable<DateTimeOffset> UntilTime { get { return _UntilTime; } set { throw new NotImplementedException(); } }

        /// <summary>
        /// If TRUE, you can queue print jobs on the computer when the printer is offline.
        /// </summary>
        public Nullable<Boolean> WorkOffline { get { return _WorkOffline; } set { throw new NotImplementedException(); } }





        /// <summary>
        /// The AddPrinterConnection WMI class method provides a connection to an existing printer on the network, and adds it to the list of available printers.
        /// </summary>
        /// <param name="Name">Friendly name for the printer.</param>
        /// <returns></returns>
        public UInt32 AddPrinterConnection(string Name) { throw new NotImplementedException(); } //TODO enum

        /// <summary>
        /// The CancelAllJobs WMI class method removes all jobs, including the one currently printing from the queue.
        /// </summary>
        /// <returns></returns>
        public UInt32 CancelAllJobs() { throw new NotImplementedException(); } //TODO enum

        //public UInt32 GetSecurityDescriptor( out  Win32_SecurityDescriptor Descriptor ) //TODO fix

        /// <summary>
        /// The Pause WMI class method pauses the print queue. No jobs can print until the queue is resumed.
        /// </summary>
        /// <returns></returns>
        public UInt32 Pause() { throw new NotImplementedException(); } //TODO enum

        /// <summary>
        /// The PrintTestPage WMI class method prints a test page. 
        /// </summary>
        /// <returns></returns>
        public UInt32 PrintTestPage() { throw new NotImplementedException(); } //TODO enum

        /// <summary>
        /// The RenamePrinter WMI class method renames a printer.
        /// </summary>
        /// <param name="NewPrinterName">New printer name.</param>
        /// <returns></returns>
        public UInt32 RenamePrinter(string NewPrinterName) { throw new NotImplementedException(); } //TODO enum

        /// <summary>
        /// The Resume WMI class method resumes a paused print queue.
        /// </summary>
        /// <returns></returns>
        public UInt32 Resume() { throw new NotImplementedException(); } //TODO enum

        /// <summary>
        /// The SetDefaultPrinter WMI class method sets the default system printer for the user calling the method.
        /// </summary>
        /// <returns></returns>
        public UInt32 SetDefaultPrinter() { throw new NotImplementedException(); }

        //public UInt32 SetSecurityDescriptor( Win32_SecurityDescriptor Descriptor){}; //TODO fix

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mbo"></param>
        public Win32_Printer(ManagementBaseObject mbo)
            : base(mbo)
        {
            _Attributes = mbo.GetUIntValue("Attributes");
            _AveragePagesPerMinute = mbo.GetUIntValue("AveragePagesPerMinute");
            _Comment = mbo.GetStringValue("Comment");
            _Default = mbo.GetBoolValue("Default");
            _DefaultPriority = mbo.GetUIntValue("DefaultPriority");
            _Direct = mbo.GetBoolValue("Direct");
            _DoCompleteFirst = mbo.GetBoolValue("DoCompleteFirst");
            _DriverName = mbo.GetStringValue("DriverName");
            _EnableBIDI = mbo.GetBoolValue("EnableBIDI");
            _EnableDevQueryPrint = mbo.GetBoolValue("EnableDevQueryPrint");
            _ExtendedDetectedErrorState = mbo.GetUshortValue("ExtendedDetectedErrorState");
            _ExtendedPrinterStatus = mbo.GetUshortValue("ExtendedPrinterStatus");
            _Hidden = mbo.GetBoolValue("Hidden");
            _KeepPrintedJobs = mbo.GetBoolValue("KeepPrintedJobs");
            _Local = mbo.GetBoolValue("Local");
            _Location = mbo.GetStringValue("Location");
            _Network = mbo.GetBoolValue("Network");
            _Parameters = mbo.GetStringValue("Parameters");
            _PortName = mbo.GetStringValue("PortName");
            _PrinterPaperNames = mbo.GetStringValueArray("PrinterPaperNames");
            _PrinterState = mbo.GetUIntValue("PrinterState");
            _PrintJobDataType = mbo.GetStringValue("PrintJobDataType");
            _PrintProcessor = mbo.GetStringValue("PrintProcessor");
            _Priority = mbo.GetUIntValue("Priority");
            _Published = mbo.GetBoolValue("Published");
            _Queued = mbo.GetBoolValue("Queued");
            _RawOnly = mbo.GetBoolValue("RawOnly");
            _SeparatorFile = mbo.GetStringValue("SeparatorFile");
            _ServerName = mbo.GetStringValue("ServerName");
            _Shared = mbo.GetBoolValue("Shared");
            _ShareName = mbo.GetStringValue("ShareName");
            _SpoolEnabled = mbo.GetBoolValue("SpoolEnabled");
            _StartTime = mbo.GetDateTimeOffsetValue("StartTime", Consts.DateTimeFormat);
            _UntilTime = mbo.GetDateTimeOffsetValue("UntilTime", Consts.DateTimeFormat);
            _WorkOffline = mbo.GetBoolValue("WorkOffline");
        }

    }


    /// <summary>
    /// 
    /// </summary>
    public class GetWin32_Printers : Win32Collection<Win32_Printer>
    {

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override ReadOnlyCollection<Win32_Printer> GetCollection()
        {
            List<Win32_Printer> tempCollection = new List<Win32_Printer>();

            foreach (var s in searcher.Get())
            {
                Win32_Printer tempListItem = new Win32_Printer(s);
                tempCollection.Add(tempListItem);
            }

            return tempCollection.AsReadOnly();
        }

        /// <summary>
        /// 
        /// </summary>
        public GetWin32_Printers() : base("SELECT * FROM Win32_Printer") { }

    }
}
